Create a new shiny app

Open RStudio and go to:

File > New Project... > New Directory > Shiny Web Application > Enter a directory name and location > Create project

R will open a new project for the shiny app, which will contain one file (app.R), which will have an example shiny app that you can run by clicking the Run App button (top right of the script panel).

This is the home of your app, and any data, pictures, etc. you need for your app to run need to be stored in the same directory so that they can be accessed by the app once it is deployed.

Note: Make sure you have shiny installed.

install.packages("shiny")

Clone the workshop

You can download a copy of this workshop, and all the code here. After downloading the file, you can unzip it and then launch the project file (CanDev_2022.Rproj) in RStudio.

App structure

app.R has three components:

  • a user interface object
  • a server function
  • a call to the shinyApp() function

You can include other code inside your app (e.g., reading data, loading packages, creating static variables). This code is run once (when the app is started), and never again.

The user interface (ui) object controls the layout and appearance of your app. The server function contains the instructions that a computer needs to build the app. Finally, the shinyApp function creates the Shiny app from an explicit UI/server pair.

Here is a high level overview of a shiny app (we will cover each part in more specifics later on):

Reactivity

Shiny is about making it easy to wire up input values from a web page, making them available to you in R, and have the results of your R code be written as output values back out to the web page.

The reactivity framework used by shiny means that:

  • You can change inputs at any time, and the outputs that are impacted will updated immediately to reflect those changes.
  • Shiny tracks “dependencies” between inputs and outputs automatically, so you don’t have to write code to track changes.
  • Using a list-like syntax, you can access inputs from the browser in the server, and write outputs from the server back to the webpage

App template

You can copy and paste almost all of the code in this workshop into your R console to launch a shiny app. Please ensure that you have installed the required packages.

install.packages("shiny")
  • Whenever you create a shiny app, you should work from a template.
  • RStudio opens all new shiny apps with a simple app that can then be modified.

Here is the basic skeleton of a shiny app:

library(shiny)

# Any code that should be executed once when the app starts. E.g., reading in a
# data file, creating static environment variables.

# Code that creates the UI of the app
ui <- fluidPage(
  # Title for your app
  titlePanel(), 
  
  sidebarLayout(
    
    # Generally, inputs are put into the sidebar
    sidebarPanel(
      
      # Inputs go here
      
      ),
    
    # And outputs are put into the mainPanel
    mainPanel(
      
      # Outputs go here
      
      )
    )
  )

# The server takes inputs from the webpage, updates outputs, and send the
# outputs back to the webpage
server <- function(input, output) { 
  
  # Server code goes here
  
  }

# Used to launch the app after defining the UI and server.
shinyApp(ui, server)

There are other templates you can use as well; but a fluid page with a sidebar layout is a good option. Fluid pages will reflow content in case there isn’t enough horizontal space. The sidebar layouts separates the page into two panels (sidebar and main), making it easier to organize inputs and outputs.

With functions like fluidRow() and column() you can have more control over the layout of an app, but for the moment we will just arrange the app into the sidebar and main panel.

Static UI elements

Aside from reactive elements, you might also want to include static elements in your UI. Static elements are things like text, or images that do not change with user input. Common tags are available from the shiny package (div(), h1(), a(), br()). Less common tags can be inserted with the tags object (e.g., tags$abbr(), tags$figcaption()).

Here is an example app with just static content:

library(shiny)

# Any code that should be executed once when the app starts. E.g., reading in a
# data file, creating static environment variables.

# Code that creates the UI of the app
ui <- fluidPage(# Title for your app
  titlePanel("A first level heading title"),
  
  sidebarLayout(
    # Generally, inputs are put into the sidebar
    sidebarPanel(
      h2("A second level heading"),
      "This small Shiny application demonstrates some static UI elements."
    ),
    
    # And outputs are put into the mainPanel
    mainPanel(
      h2("A second level header in the main panel"),
      p('My first paragraph, with some ', strong('bold'), ' text.')
      )
    )
  )

# The server takes inputs from the webpage, updates outputs, and send the
# outputs back to the webpage
server <- function(input, output) { 
  
  # Because the app is static, there is no server code!
  
  }

# Used to launch the app after defining the UI and server.
shinyApp(ui, server)

Building your app around Inputs and outputs

Until now, the apps have been simple and contained mostly static elements that we created in the UI. Shiny, however, is all about making things interactive. We do this by using inputs and outputs.

Inputs

  • Are created with an *Input() function
  • They create HTML for your app’s UI and send values from the web page to the server
Function Collects
actionButton() A button press
checkboxInput() The state of a check box (TRUE/FALSE)
checkboxGroupInput() The state of a group of check boxes (a vector of selected values)
dateInput() A single date
dateRangeInput() A range of dates (a vector of the min and max date)
fileInput() A file
numericInput() A numeric value
passwordInput() A password
radioButtons() The state of a group of radio buttons (Which option is selected)
selectInput() The current selection(s) for a drop-down list (vector of length 1, or more, that includes only selected values)
sliderInput() A single number/date/date time or a range of the same (a single value, or a vector of the min and max)
textInput() A character string (a vector of the entered text)

Syntax

*Input(inputId, label, ...)

  • inputId must be a string, and it must be unique. You cannot use special characters, other than underscores.
    • It creates the id for your input element in HTML and is used to index into the input object in the server
  • label describes what the input is for to the user and can use special characters.
  • … means that there are some other specific arguments that are required, depending on the input being used (usually this is something like value or choices).

Example

When using a sidebarLayout() I typically place most of the inputs into the sidebarPanel and use the mainPanel for my outputs. Notice that the different inputs are separated with commas inside of the sidebarPanel.

library(shiny)

ui <- fluidPage(
  sidebarLayout(
    sidebarPanel(actionButton("actionbutton", "Action Button"),
                 checkboxInput("checkboxInput", "Check box", value = TRUE),
                 checkboxGroupInput("checkboxGroupInput", "Check box group", choices = c("A", "B", "C")),
                 dateInput("dateInput", "Date"),
                 dateRangeInput("dateRangeInput", "Date Range"),
                 fileInput("fileInput", "File"),
                 numericInput("numericInput", "Number", value = 10),
                 passwordInput("passwordInput", "Password"),
                 radioButtons("radioButtons", "Radio Buttons", choices = c("A", "B", "C")),
                 selectInput("selectInput", "Drop down", choices = c("A", "B", "C")),
                 sliderInput("sliderInput", "Silder", min = 1, max = 10, value = 5),
                 textInput("textInput", "Text")
                 ),
    mainPanel(
      
      )
    )
  )

server <- function(input, output) { }

shinyApp(ui, server)

Outputs

  • Are created with *Output() functions.
  • An output is composed of two parts: a space on the UI for the output, and code on the server to create the output and render it into HTML. The functions below are used in the UI.
    • We will talk about the server component of output in a moment.
    • You must build the object in the server separately.
Function Inserts
dataTableOutput() An interactive table
tableOutput() A table
imageOutput() An image
plotOutput() A plot
textOutput() Text
verbatimTextOutput() Text
uiOutput() a Shiny UI element
htmlOutput() Raw HTML

Syntax

*Output(outputId, ...)

  • Output typically only require the outputId.
    • The ID links the output in the UI with the HTML rendered in the server.

Example

library(shiny)

ui <- fluidPage(
  sidebarLayout(
    sidebarPanel(),
    mainPanel(
      dataTableOutput("dataTableOutput"),
      tableOutput("tableOutput"),
      plotOutput("plotOutput"),
      textOutput("textOutput"),
      verbatimTextOutput("verbatimTextOutput"),
      uiOutput("uiOutput")
      )
    )
  )

server <- function(input, output) { 
  
  output$dataTableOutput <- renderDataTable({ iris })
  
  output$tableOutput <- renderTable({ iris })
  
  output$plotOutput <- renderPlot({ plot(iris) })
  
  output$textOutput <- renderText({ "Some rendered text" })
  
  output$verbatimTextOutput <- renderText({ "Some rendered text" })
  
  output$uiOutput <- renderUI({ selectInput("input", "A rendered UI input", choices = c("A", "B", "C")) })
  
  }

shinyApp(ui, server)
  • Notice that each output in the UI has a corresponding entry in the server.
  • Each output in the server is saved into a output object (output$outputId), and the UI has a corresponding entry for each ID
  • There are different rendering functions used. These turn the outputs into HTML that can be shown in the UI

Tell the server how to assemble inputs into outputs

Save object to display to output$outputId

After creating a place in the UI for the output, you need to write the code to create the output. The outputs always need to be saved into the output object. This looks like:

server <- function(input, output) { 
  
  output$outputId <- # code to create the output, e.g., code that can make a plot, or a table
  
}

Every output in the UI needs to have a value created in the server

  • for example: if you have plotOutput("plot") and tableOutput("table") in the UI, you need output$plot and output$table in the server.

Build objects with render*()

For an output to be displayed by the webpage, it must be rendered, which means it must be converted into HTML that the webpage can display. Which function you use to render an output depends on its type.

Function Creates
renderDataTable() An interactive table
renderTable() A table
renderPlot() A plot
renderText() A character string
renderUI() A Shiny UI element
server <- function(input, output) { 
  
  output$plot <- renderPlot({
    
    plot(iris)
    
  })
  
  output$table <- renderDataTable({
    
    iris
    
  })
  
  # The same table but rendered as a static table. 
  
  # output$table <- renderTable({  
  #   iris
  # })
}

Access inputs with input$inputId

To make outputs interactive, you need to connect them to one or more inputs. The simplest way to do this is to filter the data using the input values. This lets you take static data (like the iris data frame) and transform it into reactive data which can drive outputs.

library(shiny)
library(tidyverse)

ui <- fluidPage(
  sidebarLayout(
    sidebarPanel(
      
      # the slider input will return a number between 1 and 100
      sliderInput("n", "Number", min = 1, max = 100, value = 10),
      
      # the select input will return a vector of all the selected species.
      selectInput("species", "Species", 
                  choices = unique(iris$Species),
                  selected = unique(iris$Species),
                  # We are letting the user select multiple values
                  multiple = TRUE)
    ),
    mainPanel(
      tableOutput("table")
    )
    )
  )

server <- function(input, output) { 
  
  output$table <- renderTable({
    
    iris %>% 
      # because species can be a vector of length 1 - 3, we will use the %in%
      # operator to compare
      filter(Species %in% input$species) %>% 
      
      # n will always be a single value
      head(., n = input$n)
    
  })
  
  }

shinyApp(ui, server)

Deploy your app

You can share a shiny app with anyone who has R and the required packages installed on their computer simply by sharing the code, and other required files, with them.

If you want to share a shiny app with the public, or someone who doesn’t have R and the required packages, you need to deploy your app to a shiny server. Shinyapps.io provides a free service that lets you upload a limited number of apps (there are paid plans with more active hours that allow for more apps to be loaded). You can look at this article for details on deploying apps to Shinyapps.io.

R&D Personnel App

To run this code, please clone the project using the instructions above.

runApp()

You can look at the source code for the shiny app in CanDev_2022/app.R.

  • App header
    • Loads required packages.
    • Read in some data from CanDev_2022/Data and does some preprocessing
  • UI
    • The app uses the layout template, which divides a fluidPage into a sidebar panel, and a main panel.
    • All our inputs are in the sidebar
      • One slider input (input$year), one multiple choice select input (input$category) and two single choice select inputs (input$coc, input$NAICS)
    • All the outputs are in the main panel
      • one plot output ("plot") and one table output ("table")
  • Server
    • In the server we create two entries into the output object using the inputs we created in the UI
      • output$plot
        • Using the renderPlot({ # Code that returns a plot}) function we can turn code that creates a plot into an output that we can display
        • To make the plot interactive, we filter the static data we loaded at the start using the inputs
      • output$table
        • Using the renderDataTable({ # Code that returns a table}) function we can turn code that creates a table (or table like object) into an output that we can display
        • To make the table interactive, we filter the static data we loaded at the start using the inputs.